`include "cpu_def.vh"

/**
 * A MIPS cpu core with sram-like interface
 */

module core(
  input clk,
  input rst,
  
  input [5:0] ext_int,

  // inst_sram interface
  output inst_sram_uncache,
  output inst_sram_req,
  input  inst_sram_addr_ok,

  output [31:0] inst_sram_addr,

  input         inst_sram_data_ok,
  input [  3:0] inst_sram_rstrb,
  input [127:0] inst_sram_rdata,

  // data_stram interface
  output data_sram_uncache,
  output data_sram_req,
  input  data_sram_addr_ok,

  output        data_sram_wr,
  output [ 1:0] data_sram_size,
  output [31:0] data_sram_addr,
  output [ 3:0] data_sram_wstrb,
  output [31:0] data_sram_wdata,

  input        data_sram_data_ok,
  input [31:0] data_sram_rdata,

  // debug interface
  output [31:0] debug_wb_pc,
  output [ 3:0] debug_wb_rf_wen,
  output [ 4:0] debug_wb_rf_wnum,
  output [31:0] debug_wb_rf_wdata
);

  /* pipeline reg and wire */
  // inst fetch
  wire        if_out_valid;
  wire [31:0] if_out_pc;
  wire [31:0] if_out_instr;
  wire        if_out_ft_tlbre;
  wire        if_out_ft_tlbi;
  wire        if_out_ft_adel;
  wire        if_out_br_pre_taken;
  wire [31:0] if_out_br_pre_pc;

  // mmu
  wire [31:0] instr_vaddr;
  wire        instr_vaddr_valid;
  wire        itlb0_flush;
  wire        itlb0_stall;
  wire [31:0] instr_paddr;
  wire        instr_paddr_valid;
  wire        instr_uncache;
  wire        instr_tlb_refill;
  wire        instr_tlb_invalid;

  wire [31:0] data_vaddr;
  wire        data_vaddr_valid;
  wire        dtlb0_flush;
  wire        dtlb0_stall;
  wire        is_store  ;
  wire        data_uncache;
  wire [31:0] data_paddr;
  wire        data_paddr_valid;
  wire        data_tlb_refill;
  wire        data_tlb_invalid;
  wire        data_tlb_modified;

  wire        tlbwi_taken;
  wire        tlbwr_taken;

  wire [31:0] cp0_index_rdata   ;
  wire [31:0] cp0_random_rdata  ;
  wire [31:0] cp0_entrylo0_rdata;
  wire [31:0] cp0_entrylo1_rdata;
  wire [31:0] cp0_entryhi_rdata ;
  wire [31:0] cp0_config0_rdata ;

  wire [31:0] cp0_index_wdata   ;
  wire [31:0] cp0_entrylo0_wdata;
  wire [31:0] cp0_entrylo1_wdata;
  wire [31:0] cp0_entryhi_wdata ; 

  // backend
  wire backend_redirect_taken;
  wire backend_redirect_is_br;
  wire [31:0] backend_redirect_pc; 
  wire [31:0] backend_redirect_ds_pc; 
  wire frontend_stall;
  wire frontend_flush;

  wire        backend_branch;
  wire        backend_branch_taken;
  wire [31:0] backend_branch_pc;
  wire [31:0] backend_branch_target_pc;

  
  frontend mycpu_frontend(
    .clk (clk),
    .rst (rst),

    // backend
    .backend_redirect_taken(backend_redirect_taken),
    .backend_redirect_is_br(backend_redirect_is_br),
    .backend_redirect_pc   (backend_redirect_pc   ),
    .backend_redirect_ds_pc(backend_redirect_ds_pc),
    .de_flush  (frontend_flush),
    .de_stall  (frontend_stall),

    .backend_branch          (backend_branch          ),
    .backend_branch_taken    (backend_branch_taken    ),
    .backend_branch_pc       (backend_branch_pc       ),
    .backend_branch_target_pc(backend_branch_target_pc),
    
    .valid_o(if_out_valid),
    .pc_o   (if_out_pc),
    .instr_o(if_out_instr),
    .ft_tlbre_o(if_out_ft_tlbre),
    .ft_tlbi_o(if_out_ft_tlbi),
    .ft_adel_o(if_out_ft_adel),
    .br_pre_taken_o(if_out_br_pre_taken),
    .br_pre_pc_o(if_out_br_pre_pc),

    // mmu
    .instr_vaddr(instr_vaddr),
    .instr_vaddr_valid(instr_vaddr_valid),
    .itlb0_flush(itlb0_flush),
    .itlb0_stall(itlb0_stall),
    
    .instr_uncache(instr_uncache),
    .instr_paddr(instr_paddr),
    .instr_paddr_valid(instr_paddr_valid),
    .instr_tlb_refill(instr_tlb_refill),
    .instr_tlb_invalid(instr_tlb_invalid),
    
    // inst sram interface
    .inst_sram_req    (inst_sram_req    ),
    .inst_sram_uncache(inst_sram_uncache),
    .inst_sram_addr   (inst_sram_addr   ),
    .inst_sram_addr_ok(inst_sram_addr_ok),
    .inst_sram_data_ok(inst_sram_data_ok),
    .inst_sram_rstrb  (inst_sram_rstrb  ),
    .inst_sram_rdata  (inst_sram_rdata  )
  );

  backend mycpu_backend(
    .clk(clk),
    .rst(rst),
    .ext_int(ext_int),

    .if_out_valid       (if_out_valid   ),
    .if_out_pc          (if_out_pc      ),
    .if_out_instr       (if_out_instr   ),
    .if_out_ft_tlbre    (if_out_ft_tlbre),
    .if_out_ft_tlbi     (if_out_ft_tlbi ),
    .if_out_ft_adel     (if_out_ft_adel ),
    .if_out_br_pre_taken(if_out_br_pre_taken),
    .if_out_br_pre_pc   (if_out_br_pre_pc),
    .frontend_stall     (frontend_stall ),
    .frontend_flush     (frontend_flush ),

    .dtlb0_flush(dtlb0_flush),
    .dtlb0_stall(dtlb0_stall),

    .data_vaddr      (data_vaddr      ),
    .data_vaddr_valid(data_vaddr_valid),
    .is_store        (is_store        ),
    .tlbwi_taken     (tlbwi_taken     ),
    .tlbwr_taken     (tlbwr_taken     ),

    .data_uncache     (data_uncache     ),
    .data_paddr       (data_paddr       ),
    .data_paddr_valid (data_paddr_valid ),
    .data_tlb_refill  (data_tlb_refill  ),
    .data_tlb_invalid (data_tlb_invalid ),
    .data_tlb_modified(data_tlb_modified),

    .cp0_index_rdata   (cp0_index_rdata   ),
    .cp0_random_rdata  (cp0_random_rdata  ),
    .cp0_entrylo0_rdata(cp0_entrylo0_rdata),
    .cp0_entrylo1_rdata(cp0_entrylo1_rdata),
    .cp0_entryhi_rdata (cp0_entryhi_rdata ),
    .cp0_config0_rdata (cp0_config0_rdata ),

    .cp0_index_wdata   (cp0_index_wdata   ),
    .cp0_entrylo0_wdata(cp0_entrylo0_wdata),
    .cp0_entrylo1_wdata(cp0_entrylo1_wdata),
    .cp0_entryhi_wdata (cp0_entryhi_wdata ),

    .backend_redirect_taken(backend_redirect_taken),
    .backend_redirect_is_br(backend_redirect_is_br),
    .backend_redirect_pc   (backend_redirect_pc   ),
    .backend_redirect_ds_pc(backend_redirect_ds_pc),

    .backend_branch          (backend_branch          ),
    .backend_branch_taken    (backend_branch_taken    ),
    .backend_branch_pc       (backend_branch_pc       ),
    .backend_branch_target_pc(backend_branch_target_pc),

    .data_sram_uncache(data_sram_uncache),
    .data_sram_req    (data_sram_req    ),
    .data_sram_addr_ok(data_sram_addr_ok),
    .data_sram_wr     (data_sram_wr     ),
    .data_sram_size   (data_sram_size   ),
    .data_sram_addr   (data_sram_addr   ),
    .data_sram_wstrb  (data_sram_wstrb  ),
    .data_sram_wdata  (data_sram_wdata  ),
    .data_sram_rdata  (data_sram_rdata  ),
    .data_sram_data_ok(data_sram_data_ok),
    
    .debug_wb_pc      (debug_wb_pc      ),
    .debug_wb_rf_wen  (debug_wb_rf_wen  ),
    .debug_wb_rf_wnum (debug_wb_rf_wnum ),
    .debug_wb_rf_wdata(debug_wb_rf_wdata)
  );

  mmu mycpu_mmu(
    .clk(clk),
    .rst(rst),
    .itlb0_flush(itlb0_flush),
    .itlb0_stall(itlb0_stall),

    .instr_vaddr(instr_vaddr),
    .instr_vaddr_valid(instr_vaddr_valid),
    
    .instr_uncache(instr_uncache),
    .instr_paddr(instr_paddr),
    .instr_paddr_valid(instr_paddr_valid),
    .instr_tlb_refill(instr_tlb_refill),
    .instr_tlb_invalid(instr_tlb_invalid),

    .dtlb0_flush(dtlb0_flush),
    .dtlb0_stall(dtlb0_stall),

    .data_vaddr(data_vaddr),
    .data_vaddr_valid(data_vaddr_valid),
    .is_store  (is_store  ),

    .data_uncache     (data_uncache     ),
    .data_paddr       (data_paddr       ),
    .data_paddr_valid (data_paddr_valid ),
    .data_tlb_refill  (data_tlb_refill  ),
    .data_tlb_invalid (data_tlb_invalid ),
    .data_tlb_modified(data_tlb_modified),

    .tlbwi_taken(tlbwi_taken),
    .tlbwr_taken(tlbwr_taken),

    .cp0_index_rdata   (cp0_index_rdata   ),
    .cp0_random_rdata  (cp0_random_rdata  ),
    .cp0_entrylo0_rdata(cp0_entrylo0_rdata),
    .cp0_entrylo1_rdata(cp0_entrylo1_rdata),
    .cp0_entryhi_rdata (cp0_entryhi_rdata ),
    .cp0_config0_rdata (cp0_config0_rdata ),

    .cp0_index_wdata   (cp0_index_wdata   ),
    .cp0_entrylo0_wdata(cp0_entrylo0_wdata),
    .cp0_entrylo1_wdata(cp0_entrylo1_wdata),
    .cp0_entryhi_wdata (cp0_entryhi_wdata )
  );

endmodule
